﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Activities;
using System.Activities.Core.Presentation;
using System.Activities.Presentation;
using System.Activities.Statements;
using System.Activities.XamlIntegration;
using System.Activities.Presentation.Model;
using System.Activities.Presentation.Services;
using System.Activities.Presentation.View;
using System.Activities.Presentation.Debug;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Threading;
using System.ComponentModel;
using Entities = Vision.Core.Entities;

namespace Vision.VisionWorkshop.Controls
{
    /// <summary>
    /// Interaction logic for EnterpriseActivityDesigner.xaml
    /// </summary>
    public partial class EnterpriseActivityDesigner : UserControl, INotifyPropertyChanged
    {
		#region INotifyPropertyChanged implementation
		public event PropertyChangedEventHandler PropertyChanged;

		private void RaisePropertyChanged(string propertyName)
		{
			if (PropertyChanged != null)
				PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
		}
		#endregion

		private Entities.Activities.VisionActivity _enterpriseActivity = null;
		private WorkflowDesigner _workflowDesigner = null;
        
        public delegate void DesignerUpdate(UIElement propertyWindow);
        public event DesignerUpdate DesignerUpdateEvent;
		public event EventHandler DesignerChangedEvent;

		bool _dirty = false;

		public bool IsDirty { get { return _dirty; } }

		public string Display
		{
			get
			{
				if (_enterpriseActivity == null)
					return "Untitled";
				else
					return string.Format("{0}{1}", _enterpriseActivity.Name, _dirty ? "*" : "");
			}
		}

		public Entities.Activities.VisionActivity EnterpriseActivity
		{
			get
			{
				return _enterpriseActivity;
			}
			set
			{
				if (_enterpriseActivity != value)
				{
					detachEnterpriseActivityEvents(_enterpriseActivity);
					
					_enterpriseActivity = value;

					attachEnterpriseActivityEvents(_enterpriseActivity);

					RaisePropertyChanged("EnterpriseActivity");
					RaisePropertyChanged("Display");
				}
			}
		}

		public WorkflowDesigner WorkflowDesigner
		{
			get
			{
				return _workflowDesigner;
			}
			set
			{
				if (_workflowDesigner != value)
				{
					detachWorkFlowEvents(_workflowDesigner);

					_workflowDesigner = value;

					attachWorkFlowEvents(_workflowDesigner);

					RaisePropertyChanged("WorkflowDesigner");
				}
			}
		}


        /// <summary>
        /// 
        /// </summary>
        public EnterpriseActivityDesigner()
        {
            InitializeComponent();
            (new DesignerMetadata()).Register();                                     
        }

		#region Enterprise Activity event handling
		private void attachEnterpriseActivityEvents(Entities.Activities.VisionActivity enterpriseActivity)
		{
			if (enterpriseActivity != null)
			{
				enterpriseActivity.PropertyChanged += enterpriseActivity_PropertyChanged;
			}
		}

		private void detachEnterpriseActivityEvents(Entities.Activities.VisionActivity enterpriseActivity)
		{
			if (enterpriseActivity != null)
			{
				enterpriseActivity.PropertyChanged -= enterpriseActivity_PropertyChanged;
			}
		}

		void enterpriseActivity_PropertyChanged(object sender, PropertyChangedEventArgs e)
		{
			switch (e.PropertyName)
			{
				case "Name":
					RaisePropertyChanged("Display");
					break;
			}
		}
		#endregion

		#region WorkFlow Designer event handling
		private void attachWorkFlowEvents(System.Activities.Presentation.WorkflowDesigner workflowDesigner)
		{
			if (workflowDesigner != null)
			{
				workflowDesigner.ModelChanged += workflowDesigner_ModelChanged;
			}
		}

		private void detachWorkFlowEvents(System.Activities.Presentation.WorkflowDesigner workflowDesigner)
		{
			if (workflowDesigner != null)
			{
				workflowDesigner.ModelChanged -= workflowDesigner_ModelChanged;
			}
		}

		void workflowDesigner_ModelChanged(object sender, EventArgs e)
		{
			if (!_dirty)
			{
				_dirty = true;
				RaisePropertyChanged("Display");
			}

			if (DesignerChangedEvent != null)
				DesignerChangedEvent(this, EventArgs.Empty);

			//if (WorkflowModelChanged != null)
			//	WorkflowModelChanged(this, EventArgs.Empty);
		}
		#endregion

		/// <summary>
        /// 
        /// </summary>
        public void New()
        {                                    
            this.EnterpriseActivity = new Entities.Activities.VisionActivity();
            this.WorkflowDesigner = new WorkflowDesigner();

			this.EnterpriseActivity.Name = "Activity";

            ActivityBuilder ab = new ActivityBuilder();
            ab.Name = "Activity";
            ab.Implementation = new Flowchart();

            this.WorkflowDesigner.Load(ab);                        
            this.ctlViewWindow.Content = this.WorkflowDesigner.View;

            if (this.DesignerUpdateEvent != null){
                this.DesignerUpdateEvent(this.WorkflowDesigner.PropertyInspectorView);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="enterpriseActivity"></param>
        public void Open(Entities.Activities.VisionActivity enterpriseActivity)
        {
            this.EnterpriseActivity = enterpriseActivity;
            
            this.WorkflowDesigner = new WorkflowDesigner();
            this.WorkflowDesigner.Text = enterpriseActivity.Activity.ToString();
            this.WorkflowDesigner.Load();            

			this.ctlViewWindow.Content = this.WorkflowDesigner.View;
            if (this.DesignerUpdateEvent != null){
				this.DesignerUpdateEvent(this.WorkflowDesigner.PropertyInspectorView);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public Entities.Activities.VisionActivity Save()
        {
            dynamic root = this.WorkflowDesigner.Context.Services.GetService<ModelService>().Root.GetCurrentValue();
            if (root != null){
                this.EnterpriseActivity.Name = root.Name;
				this.EnterpriseActivity.Description = this.EnterpriseActivity.Description ?? root.Name;
            }
                
            this.WorkflowDesigner.Flush();                                   
            this.EnterpriseActivity.Activity = System.Xml.Linq.XElement.Parse(this.WorkflowDesigner.Text);
            return this.EnterpriseActivity;
        }

        /// <summary>
        /// 
        /// </summary>
        public void Run()
        {
            this.WorkflowDesigner.Flush();
            DynamicActivity dynamicActivity = (DynamicActivity)ActivityXamlServices.Load(System.Xml.Linq.XElement.Parse(this.WorkflowDesigner.Text).CreateReader());
            if (dynamicActivity != null){
                WorkflowInvoker invoker = new WorkflowInvoker(dynamicActivity);
                ThreadPool.QueueUserWorkItem(new WaitCallback((context) =>{
                    Console.WriteLine("------------------------------------");
                    Console.WriteLine("Begin Executing Activity");
                    invoker.InvokeCompleted += delegate(object sender, InvokeCompletedEventArgs e){
                        if (e.Error != null){
                            Console.WriteLine(e.Error.ToString());
                        }
                        else{
                            Console.WriteLine("Completed Executing Activity");
                        }
                        Console.WriteLine("------------------------------------");
                        Console.Out.Flush();
                    };
                    invoker.InvokeAsync();
                }));                 
            }                                    
        }

		/// <summary>
		/// 
		/// </summary>
		public void Close()
		{
			this.WorkflowDesigner.Flush();

			DesignerView designerView = this.WorkflowDesigner.Context.Services.GetService<DesignerView>();
			ModelService modelService = this.WorkflowDesigner.Context.Services.GetService<ModelService>();

			// clean up the flow chart
			if (designerView != null && modelService != null){
				// clear the designer
				designerView.MakeRootDesigner(modelService.Root);
				Flowchart flowchart = modelService.Root.GetCurrentValue() as Flowchart;
				if (flowchart != null){
					Sequence instance = new Sequence();
					System.Activities.Presentation.WorkflowDesigner workflowDesigner = new System.Activities.Presentation.WorkflowDesigner();
					workflowDesigner.Load(instance);
					this.WorkflowDesigner = workflowDesigner;
				}

				// clear the model service
				modelService.Root.Content.ClearValue();
			}
		}

		internal void MarkAsSaved()
		{
			_dirty = false;
			RaisePropertyChanged("Display");
		}                
	}
}
